﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKArchMethodLibrary.Utils;
using TopologySearch;

namespace YJKFloor.Utility
{
	public class FloorEditCommon
	{
		public FloorEditCommon(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
			this.m_Doc = this.m_Revit.Application.ActiveUIDocument.Document;
		}

		public void GetFloorLoopAndOpeningLoop(Element floor, ref List<List<Curve>> floorLoops, ref List<List<Curve>> openingLoops)
		{
			new List<GeometryObject>();
			Options options = this.m_Revit.Application.Application.Create.NewGeometryOptions();
			GeometryElement geometryElement = floor.get_Geometry(options);
			if (null == geometryElement)
			{
				return;
			}
			List<List<Curve>> list = new List<List<Curve>>();
			foreach (GeometryObject geometryObject in geometryElement)
			{
				if (!(geometryObject.GetType() != typeof(Solid)))
				{
					Solid solid = geometryObject as Solid;
					if (solid != null)
					{
						List<List<Curve>> list2 = new List<List<Curve>>();
						this.GetBoundary(solid, ref list2);
						for (int i = 0; i < list2.Count; i++)
						{
							List<Curve> list3 = new List<Curve>();
							new List<Curve>();
							list3.AddRange(list2[i]);
							for (int j = i + 1; j < list2.Count; j++)
							{
								int num = this.Intersect2Polygon(list2[i], list2[j]);
								if (num != 0)
								{
									if (num != 1)
									{
										list2.Add(list2[i]);
										list2.RemoveAt(i);
										i--;
										list3.Clear();
										break;
									}
									if (list2[j].Count > 0)
									{
										openingLoops.Add(list2[j]);
									}
									list2.RemoveAt(j);
									j--;
								}
							}
							if (list3.Count > 0)
							{
								list.Add(list3);
							}
						}
					}
				}
			}
			this.GetFullFloorLoop(list, openingLoops, ref floorLoops);
		}

		private void GetFullFloorLoop(List<List<Curve>> floorLoops, List<List<Curve>> openingLoops, ref List<List<Curve>> fullFloorLoops)
		{
			try
			{
				List<List<Curve>> list = new List<List<Curve>>();
				list.AddRange(floorLoops);
				list.AddRange(openingLoops);
				List<Pole2D> list2 = new List<Pole2D>();
				foreach (List<Curve> list3 in list)
				{
					foreach (Curve curve in list3)
					{
						XYZ hyendPoint = curve.GetEndPoint(0);
						XYZ hyendPoint2 = curve.GetEndPoint(1);
						Pole2D item;
						if (curve.GetType() == typeof(Arc))
						{
							Arc arc = curve as Arc;
							item = Pole2D.NewStructure2DPole(ElementId.InvalidElementId, hyendPoint, hyendPoint2, arc.Center, arc.Normal, 0.0, 0.0);
						}
						else
						{
							item = Pole2D.NewStructure2DPole(ElementId.InvalidElementId, hyendPoint, hyendPoint2, 0.0, 0.0);
						}
						list2.Add(item);
					}
				}
				StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_Revit);
				fullFloorLoops = structureLoopSearcher.GetFullFloorEdgeLoops(list2, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
			}
			catch (Exception)
			{
				fullFloorLoops = floorLoops;
			}
		}

		public void NewOpeing(List<List<Curve>> openingLoops, List<List<Curve>> floorLoops, List<Floor> floors)
		{
			Transaction transaction = null;
			transaction = new Transaction(this.m_Doc);
			transaction.Start("new opeing");
			foreach (List<Curve> list in openingLoops)
			{
				int num = -1;
				CurveArray curveArray = null;
				try
				{
					curveArray = new CurveArray();
					foreach (Curve curve in list)
					{
						curveArray.Append(curve);
					}
					num = this.FindHost(list, floorLoops);
					if (num == -1)
					{
						continue;
					}
				}
				catch (Exception)
				{
					continue;
				}
				try
				{
					this.m_Doc.Create.NewOpening(floors[num], curveArray, false);
				}
				catch (Exception)
				{
				}
			}
			transaction.Commit();
		}

		public int FindHost(List<Curve> subOpeningLoop, List<List<Curve>> floorLoops)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in subOpeningLoop)
			{
				list.Add(curve.GetEndPoint(0));
			}
			for (int i = 0; i < floorLoops.Count; i++)
			{
				bool flag = true;
				foreach (XYZ pt in list)
				{
					if (!this.PointInPloygon(floorLoops[i], pt, true))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					return i;
				}
			}
			return -1;
		}

		public bool floorInOpening(List<Curve> floorLoop, List<List<Curve>> openingLoops)
		{
			if (openingLoops.Count < 1)
			{
				return false;
			}
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in floorLoop)
			{
				list.Add(curve.GetEndPoint(0));
			}
			foreach (XYZ pt in list)
			{
				for (int i = 0; i < openingLoops.Count; i++)
				{
					if (!this.PointInPloygon(openingLoops[i], pt, true))
					{
						return false;
					}
				}
			}
			return true;
		}

		public void DeleteElement(Element element)
		{
			Transaction transaction = new Transaction(this.m_Doc);
			transaction.Start("delete element");
			this.m_Doc.Delete(element.Id);
			transaction.Commit();
		}

		public void GetBoundary(Solid solid, ref List<List<Curve>> singleBoundary)
		{
			PlanarFace planarFace = null;
			FaceArray faces = solid.Faces;
			foreach (object obj in faces)
			{
				Face face = (Face)obj;
				PlanarFace planarFace2 = face as PlanarFace;
				if (null != planarFace2 && planarFace2.FaceNormal().IsAlmostEqualTo(XYZ.BasisZ) && (null == planarFace || planarFace2.Origin.Z < planarFace.Origin.Z))
				{
					planarFace = planarFace2;
				}
			}
			if (null != planarFace)
			{
				EdgeArrayArray edgeLoops = planarFace.EdgeLoops;
				foreach (object obj2 in edgeLoops)
				{
					EdgeArray edgeArray = (EdgeArray)obj2;
					List<Curve> list = new List<Curve>();
					foreach (object obj3 in edgeArray)
					{
						Edge edge = (Edge)obj3;
						Curve curve = edge.AsCurve();
						if (curve.GetType() == typeof(Line) || curve.GetType() == typeof(Arc))
						{
							list.Add(curve);
						}
					}
					singleBoundary.Add(list);
				}
			}
		}

		public void GetOldInfo(Floor floor, ref FloorType floorType, ref Level level, ref double offset, ref bool isStruct)
		{
			int num = floor.get_Parameter(BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL).AsInteger();
			isStruct = true;
			if (num == 0)
			{
				isStruct = false;
			}
			ElementId elementId = floor.get_Parameter(BuiltInParameter.LEVEL_PARAM).AsElementId();
			level = (this.m_Doc.GetElement(elementId) as Level);
			offset = floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).AsDouble();
			floorType = floor.FloorType;
		}

		public List<Opening> GetOpeningByFloor(ElementId hostId)
		{
			List<Opening> list = new List<Opening>();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Doc);
			ICollection<Element> collection = filteredElementCollector.OfClass(typeof(Opening)).ToElements();
			foreach (Element element in collection)
			{
				Opening opening = element as Opening;
				if (opening.Host != null && opening.Host.Id.IntegerValue == hostId.IntegerValue)
				{
					list.Add(opening);
				}
			}
			return list;
		}

		public int Intersect2Polygon(List<Curve> polygon1, List<Curve> polygon2)
		{
			if (polygon1.Count == 0 || polygon2.Count == 0)
			{
				return 0;
			}
			List<XYZ> list = this.GetverticesByPolygon(polygon1);
			List<XYZ> list2 = this.GetverticesByPolygon(polygon2);
			if (Geometry.PointInPloygon(list, list2[0], 0.0001, 0.0001) != -1)
			{
				return 1;
			}
			if (Geometry.PointInPloygon(list2, list[0], 0.0001, 0.0001) != -1)
			{
				return -1;
			}
			return 0;
		}

		public bool PointInPloygon(List<Curve> polygon, XYZ pt, bool includeBoundary)
		{
			List<XYZ> vecPolypt = this.GetverticesByPolygon(polygon);
			int num = Geometry.PointInPloygon(vecPolypt, pt, 0.0001, 0.0001);
			if (includeBoundary)
			{
				if (num != -1)
				{
					return true;
				}
			}
			else if (num == 1)
			{
				return true;
			}
			return false;
		}

		public Floor CreateFloor(List<Curve> edgeLoop, FloorType floorType, Level level, double offset, bool isStruct)
		{
			CurveArray curveArray = new CurveArray();
			foreach (Curve curve in edgeLoop)
			{
				curveArray.Append(curve);
			}
			Transaction transaction = null;
			transaction = new Transaction(this.m_Doc);
			transaction.Start("new floor");
			Floor result;
			try
			{
				Floor floor = this.m_Doc.Create.NewFloor(curveArray, floorType, level, isStruct, XYZ.BasisZ);
				if (floor != null)
				{
					floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(offset);
				}
				transaction.Commit();
				result = floor;
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
				result = null;
			}
			return result;
		}

		public List<XYZ> GetverticesByPolygon(List<Curve> polygon)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in polygon)
			{
				IList<XYZ> list2 = curve.Tessellate();
				int count = list2.Count;
				for (int i = 0; i < count - 1; i++)
				{
					XYZ xyz = list2[i];
					list.Add(new XYZ(xyz.X, xyz.Y, 0.0));
				}
			}
			return list;
		}

		private ExternalCommandData m_Revit;

		private Document m_Doc;
	}
}
